﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading.Tasks;

namespace RESTfulCore
{
    public class RestClientConfigurationSection : ConfigurationSection
    {
        public static RestClientConfigurationSection Config()
        {
            return (RestClientConfigurationSection)ConfigurationManager.GetSection("RestClientSection");
        }

        [ConfigurationProperty("endpoints", IsRequired = true)]
        [ConfigurationCollection(typeof(EndPoint), AddItemName = "endpoint")]
        public EndPointCollection EndPoints => (EndPointCollection)this["endpoints"];
    }

    public class EndPoint : ConfigurationElement
    {
        private const string AddressAttribute = "address";
        private const string NameAttribute = "name";
        private const string ContractAttriute = "contract";
        private const string TimeoutAttribute = "timeout";
        private const string MaxBufferSizeAttribute = "maxBufferSize";

        [ConfigurationProperty(AddressAttribute, IsRequired = true)]
        public string Address
        {
            get { return this[AddressAttribute] as string; }
            set { this[AddressAttribute] = value; }
        }

        [ConfigurationProperty(NameAttribute, IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return this[NameAttribute] as string; }
            set { this[NameAttribute] = value; }
        }

        [ConfigurationProperty(ContractAttriute, IsRequired = true)]
        public string Contract
        {
            get { return this[ContractAttriute] as string; }
            set { this[ContractAttriute] = value; }
        }

        [ConfigurationProperty(TimeoutAttribute, IsRequired = false, DefaultValue = "00:00:30")]
        public TimeSpan Timeout
        {
            get
            {
                TimeSpan timeSpan;
                if (TimeSpan.TryParse(this[TimeoutAttribute] as string, out timeSpan))
                    return timeSpan;
                return new TimeSpan(0, 0, 10);
            }
            set { this[TimeoutAttribute] = value; }
        }

        [ConfigurationProperty(MaxBufferSizeAttribute, IsRequired = false, DefaultValue = 65536)]
        public int MaxBufferSize
        {
            get
            {
                const int buffer = 65536;

                if (this[MaxBufferSizeAttribute] != null)
                {
                    int maxBufferSize;
                    if (int.TryParse(this[MaxBufferSizeAttribute] as string, out maxBufferSize))
                        return maxBufferSize;
                    return buffer;
                }

                return buffer;
            }
        }
    }

    public class EndPointCollection : ConfigurationElementCollection
    {

        public EndPoint this[int index] => (EndPoint)BaseGet(index);

        public new EndPoint this[string key]
        {
            get
            {
                EndPoint endPoint = null;
                Parallel.For(0, Count, l =>
                {
                    int i = l;
                    if (this[i].Contract == key)
                    {
                        endPoint = this[i];
                    }
                });

                if (endPoint == null)
                    throw new KeyNotFoundException();

                return endPoint;
            }
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((EndPoint)element).Contract;
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new EndPoint();
        }
    }
}
